前言:架構對於初學者來說,非常重要,但是非常難學,當初我在學習時,雖然網路上有很多文章,但每一個都不知道再供三小。即便我這篇文章,或許你也會聽不懂、看不懂。但別放棄,架構真的太、太、太重要!!一定要至少想辦法學會 MVP,再前往 MVVM
Android app 的【架構】目前分為 MVC MVP MVVM
- 推薦指數 MVVM > MVP > MVC
- 困難指數 MVVM > MVP > MVC
Q:架構是什麼?
A:該架構指的就是 程式碼 的 架構
-
可以理解成 => 達到同樣畫面效果的同時,我們的程式碼要整理成什麼樣子?
我們拿昨天最後的程式碼和畫面為例
我們把所有【畫面顯示】【判斷句】【邏輯】甚至【資料庫請求】等等都寫在 onCreate 裡面,未來程式碼幾千行的時候,會導致你自己都看不懂自己在寫什麼?
即使看得懂,其他人來維護的時候,也會傻眼。
但是當你告訴別人:我這個專案是以 MVP 架構來寫的,人家至少心裡就有個底知道你的排版大概長什麼樣子。
MVP 就是下列三個單字的縮寫
各自負責不同的程式碼
拿昨天帳號密碼的例子來解釋,想法上應該是
-
View 偵測到有人按下登入按鈕
-
請 Presenter 判斷一下帳號密碼是否正確
-
若正確 -> 請 View 顯示成功
-
若錯誤 -> 請 View 顯示失敗
View 的工作
:Presenter 要我顯示什麼,我就顯示什麼,但我可以決定要用 TextView 顯示,還是用 Toast( 吐司 ) 顯示。 (只負責畫面)
Presenter 的工作
:View 會丟給我帳號密碼,我比對帳號是否為 1234,密碼是否為 5678,接著叫 View 顯示成功或失敗。我並不知道他是用 TextView 顯示,還是用 Toast( 吐司 )顯示。 (只負責邏輯:運算、判斷)
大概了解之後 我們看一下程式碼是怎麼完成這些分工的!
我們必須要有 View 跟 Presenter
-
View 就是 MainActivity
-
Presenter 需要自己創
創一個 Class 名叫 Presenter
class Presenter {
}
創一個 fun 並傳進 account 和 password
class Presenter {
fun compare(account: String, password: String) {
}
}
比較帳號密碼是否是我們要的
class Presenter {
fun compare(account: String, password: String) {
if (account == "1234" && password == "5678") {
// Todo 需要通知 MainActivity 顯示成功
} else {
// Todo 需要通知 MainActivity 顯示成功
}
}
}
Q:要怎麼通知 MainActivity 呢?
A:只好在 View 創造 Presenter 物件的時候,把自己丟進去
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 創一個 Preseneter 物件並丟進自己(this)
val presenter = Presenter(this)
}
class Presenter(val view: MainActivity) { // 取得 MainActivity 物件
fun compare(account: String, password: String) {
if (account == "1234" && password == "5678") {
// Todo 需要通知 MainActivity 顯示成功
} else {
// Todo 需要通知 MainActivity 顯示成功
}
}
}
這樣 Presenter 也拿到 View 的物件
但是我們還沒有寫要如何顯示成功和失敗,讓我們先在 View 寫兩個 function
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val presenter = Presenter(this)
}
fun showSuccess(){
Toast.makeText(this,"登入成功",Toast.LENGTH_SHORT).show()
}
fun showFailure(){
Toast.makeText(this,"登入失敗",Toast.LENGTH_SHORT).show()
}
這樣 Presenter 也知道要呼叫 View 的什麼方法了!
class Presenter(val view: MainActivity) {
fun compare(account: String, password: String) {
if (account == "1234" && password == "5678") {
view.showSuccess() // 請 View 顯示成功
} else {
view.showFailure() // 請 View 顯示失敗
}
}
}
最後就是一開始要將用戶輸入的 帳號、密碼,交給 Presenter 處理
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val presenter = Presenter(this)
btn_login.setOnClickListener { // 按下 login
val account = et_account.text.toString()
val password = et_password.text.toString()
// 將 EditText 裡的帳號密碼交給 Presenter
presenter.compare(account, password)
}
btn_reset.setOnClickListener {
et_account.text.clear()
et_password.text.clear()
}
}
fun showSuccess() {
Toast.makeText(this, "登入成功", Toast.LENGTH_SHORT).show()
}
fun showFailure() {
Toast.makeText(this, "登入失敗", Toast.LENGTH_SHORT).show()
}
最後大概是這樣的邏輯
【其實上述的例子不是真正的 MVP 架構,但是精神已經有到。】
其實最讓新手學習困難的點是,View 和 Presenter 到底是怎麼溝通的?
不同點
:真正的 MVP 架構,Presenter 裡面並不會像我們直接取得 MainActivity 物件的做法,而是利用一個介面( interface ) 做為兩者溝通的橋梁
不完整點
:我們還沒有使用到 Model,這部分我們之後會談到。